package com.zeyu.framework.core.persistence.entity;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.zeyu.framework.utils.Reflections;
import com.zeyu.framework.utils.StringUtils;

import org.hibernate.validator.constraints.Length;

import java.util.List;

import javax.validation.constraints.NotNull;

/**
 * 数据Entity类
 */
public abstract class TreeEntity<T> extends DataEntity<T> {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * UID
     */
    private static final long serialVersionUID = 1L;

    // ================================================================
    // Fields
    // ================================================================

    // 父级编号
    protected T parent;
    // 所有父级编号
    protected String parentIds;
    // 名称
    protected String name;
    // 排序
    protected Integer sort;

    // 父名称,数据库无关,经常使用,通过对象返回
    private String parentName;

    // ================================================================
    // Constructors
    // ================================================================

    /**
     */
    public TreeEntity() {
        super();
        this.sort = 30;
    }

    /**
     */
    public TreeEntity(String id) {
        super(id);
    }

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 父对象，只能通过子类实现，父类实现mybatis无法读取
     *
     * @return 父对象
     */
    @JsonBackReference
    @NotNull
    public abstract T getParent();

    /**
     * 父对象，只能通过子类实现，父类实现mybatis无法读取
     */
    public abstract void setParent(T parent);

    /**
     * 默认存在id为1的节点为根节点，不允许删除.
     *
     * @param id 节点id
     * @return 是否为根节点
     */
    @JsonIgnore
    public static boolean isRoot(String id) {

        return StringUtils.isBlank(id) || StringUtils.equalsIgnoreCase(id, DEFAULT_ROOT_ID);

    }

    @JsonIgnore
    public static <V extends TreeEntity> void sortList(List<V> list, List<V> sourceList, String parentId, boolean cascade) {
        for (int i = 0; i < sourceList.size(); i++) {
            V e = sourceList.get(i);
            TreeEntity parent = (TreeEntity) e.getParent();
            if (parent != null && parent.getId() != null && parent.getId().equals(parentId)) {
                list.add(e);
                if (cascade) {
                    // 判断是否还有子节点, 有则继续获取子节点
                    for (int j = 0; j < sourceList.size(); j++) {
                        TreeEntity child = sourceList.get(j);
                        TreeEntity childParent = (TreeEntity) child.getParent();
                        if (childParent != null && childParent.getId() != null && childParent.getId().equals(e.getId())) {
                            sortList(list, sourceList, e.getId(), true);
                            break;
                        }
                    }
                }
            }
        }
    }

    @JsonIgnore
    public static String getRootId() {
        return DEFAULT_ROOT_ID;
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    @Length(min = 1, max = 2000)
    public String getParentIds() {
        return parentIds;
    }

    public void setParentIds(String parentIds) {
        this.parentIds = parentIds;
    }

    @Length(min = 1, max = 100)
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSort() {
        return sort;
    }

    public void setSort(Integer sort) {
        this.sort = sort;
    }

    public String getParentId() {
        String id = null;
        if (parent != null) {
            id = (String) Reflections.getFieldValue(parent, "id");
        }
        return StringUtils.isNotBlank(id) ? id : "0";
    }

    public String getParentName() {
        if (parent != null) {
            return ((TreeEntity) parent).getName();
        }
        return parentName;
    }

    public void setParentName(String parentName) {
        this.parentName = parentName;
    }

    // ================================================================
    // Private Methods
    // ================================================================

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================
}
